#    This file is part of robo-ircbot.
#
#    robo-ircbot is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    robo-ircbot is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with robo-ircbot.  If not, see <http://www.gnu.org/licenses/>.

package Robo::ModuleLoader;
use strict;
use warnings;
use App::Modular;
use Data::Dumper;

# Constructor
sub new
{
        my ($class, $robo, $cfg) = @_;
        
        my $self = { };
        
        $self->{robo} = $robo;
        $self->{cfg} = $cfg;
        $self->{call} = { };
        $self->{events} = { };
        $self->{mod} = undef;
        
        bless($self);
        return $self;
}

# Load our modules.
sub load_modules
{
        my $self = shift;
        
        $self->{robo}->log("Loading all modules...");
        
        # Create App::Modular instance and set directory and extension.
        if (!$self->{mod}) {
                $self->{mod} = instance App::Modular;
                $self->{mod}->module_directory('./modules/');
                $self->{mod}->module_extension('.pm');
                $self->{mod}->module_autoload(1);
        }
        
        # Register all modules in module_directory.
        eval {
                $self->{mod}->modules_register_all();
        };
        if ($@) { chomp($@); $self->{robo}->log($@); }
        
        # Get array of loaded modules.
        my @loaded = $self->{mod}->modules();
        
        # For each module, add to call hash and add to whatever event hash
        # it belongs.
        foreach my $mod (@loaded) {
                $self->{call}->{$mod} = $self->{mod}->module($mod);

                my @events = split(/ /, $self->{call}->{$mod}->events());
                
                # Add module to each event type listing.
                foreach (@events) {
                        my $event = lc($_);
                        
                        # Create array in the event hash.
                        if (!$self->{events}->{$event}) {
                                $self->{events}->{$event} = [ ];
                        }
                        
                        # Add the module name to the array.
                        push(@{$self->{events}->{$event}}, $mod);
                }
        }
}

# Reload our modules.
sub reload_modules
{
        my $self = shift;
        
        $self->{robo}->log(":: Reloading modules...");
        
        $self->{events} = { };
        $self->{call} = { };
        $self->{mod}->modules_deregister_all();
        
        $self->load_modules();
}

# Load a single module.
sub load_module
{
        my ($self, $mod) = @_;

        if (!-e "./modules/".$mod.".pm") { return 0; }

        # Register the module.  We trap error messages so that we
        # can log for debugging purposes.
        eval {
                $self->{mod}->module_register($mod);
        };
        if ($@) { chomp($@); $self->{robo}->log($@); }

        # Add module reference to the call hash.
        $self->{call}->{$mod} = $self->{mod}->module($mod);

        # Get the events the module wishes to receive.
        my @events = split(/ /, $self->{call}->{$mod}->events());
                
        # Add module to each event type listing.
        foreach (@events) {
                my $event = lc($_);
                
                # Create array in the event hash.
                if (!$self->{events}->{$event}) {
                        $self->{events}->{$event} = [ ];
                }
                
                # Add the module name to the array.
                push(@{$self->{events}->{$event}}, $mod);
        }

        return 1;
}

# Unload a single module.
sub unload_module
{
        my ($self, $mod) = @_;

        if (!$self->{call}->{$mod}) { return 0; }

        $self->{robo}->log("Unloading ".$mod."!");        
        $self->{mod}->module_deregister($mod);
        delete $self->{call}->{$mod};

        foreach my $event (%{$self->{events}}) {
                my $i = 0;
                foreach my $m (@{$self->{events}->{$event}}) {
                        if ($m eq $mod) {
                                delete @{$self->{events}->{$event}}[$i];
                                $self->{robo}->log("Deleted ".$m." from events array.");
                        }
                        $i++;
                }
        }

        return 1;
}

# Reload a single module.
sub reload_module
{
        my ($self, $mod) = @_;
        
        $self->unload_module($mod);
        $self->load_module($mod);
}

1;
